﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System.Windows
{
    /// <summary>
    /// Implements a static utility class for manipulating layout in <see cref="UIElement"/>-derived objects.
    /// </summary>
    public class LayoutHelper
    {
        /// <summary>
        /// Sets the Canvas.Left and Canvas.Top dependency properties for a <see cref="UIElement"/> instance.
        /// </summary>
        /// <param name="visual">The <see cref="UIElement"/> instance to locate.</param>
        /// <param name="x">The x position of the element relative to its parent.</param>
        /// <param name="y">The y position of the element relative to its parent.</param>
        public static void SetVisualLocation(UIElement visual, double x, double y)
        {
            visual.SetValue(Canvas.LeftProperty, Double.IsNaN(x) ? 0.0 : x);
            visual.SetValue(Canvas.TopProperty, Double.IsNaN(y) ? 0.0 : y);
        }

        /// <summary>
        /// Sets the Canvas.Left, Canvas.Top, Width and Height for a given <see cref="UIElement"/> instance.
        /// </summary>
        /// <param name="visual">The <see cref="UIElement"/> instance to locate and size.</param>
        /// <param name="rect">The <see cref="System.Windows.Rect"/> to use as the bounds.</param>
        public static void SetVisualBounds(UIElement visual, Rect rect)
        {
            visual.SetValue(Canvas.LeftProperty, Double.IsNaN(rect.X) ? 0.0 : rect.X);
            visual.SetValue(Canvas.TopProperty, Double.IsNaN(rect.Y) ? 0.0 : rect.Y);
            visual.SetValue(Canvas.WidthProperty, Double.IsNaN(rect.Width) ? 0.0 : Math.Max(0.0, rect.Width));
            visual.SetValue(Canvas.HeightProperty, Double.IsNaN(rect.Height) ? 0.0 : Math.Max(0.0, rect.Height));
        }

        /// <summary>
        /// Sets the Canvas.Left, Canvas.Top, Width and Height for a given <see cref="UIElement"/> instance.
        /// </summary>
        /// <param name="visual">The <see cref="UIElement"/> instance to locate and size.</param>
        /// <param name="x">The x position of the element relative to its parent.</param>
        /// <param name="y">The y position of the element relative to its parent.</param>
        /// <param name="width">The width to apply to the element.</param>
        /// <param name="height">The height to apply to the element.</param>
        public static void SetVisualBounds(UIElement visual, double x, double y, double width, double height)
        {
            visual.SetValue(Canvas.LeftProperty, Double.IsNaN(x) ? 0.0 : x);
            visual.SetValue(Canvas.TopProperty, Double.IsNaN(y) ? 0.0 : y);
            visual.SetValue(Canvas.WidthProperty, Double.IsNaN(width) ? 0.0 : Math.Max(0.0, width));
            visual.SetValue(Canvas.HeightProperty, Double.IsNaN(height) ? 0.0 : Math.Max(0.0, height));
        }

        /// <summary>
        /// Gets the bounds of a <see cref="UIElement"/> instance, relative to its parent container.
        /// </summary>
        /// <param name="visual">The <see cref="UIElement"/> for which the bounds will be returned.</param>
        /// <returns>A <see cref="System.Windows.Rect"/> which describes the bounds of the element.</returns>
        public static Rect GetBounds(UIElement visual)
        {
            Rect rect = new Rect();
            rect.X = (double)visual.GetValue(Canvas.LeftProperty);
            rect.Y = (double)visual.GetValue(Canvas.TopProperty);
            rect.Width = (double)visual.GetValue(Canvas.WidthProperty);
            rect.Height = (double)visual.GetValue(Canvas.HeightProperty);

            if (visual is FrameworkElement)
            {
                FrameworkElement element = (FrameworkElement)visual;
                if (double.IsNaN(rect.Width)) rect.Width = element.ActualWidth;
                if (double.IsNaN(rect.Height)) rect.Height = element.ActualHeight;
            }

            return rect;
        }

        /// <summary>
        /// Aligns a <see cref="UIElement"/> instance within a given rectangle, and based on a specific size.
        /// </summary>
        /// <param name="visual">The visual to align</param>
        /// <param name="size">The logical size of the visual</param>
        /// <param name="rect">The <see cref="System.Windows.Rect"/> which describes the bounds in which to align the visual</param>
        /// <param name="alignX">The horizontal alignment within the rectangle</param>
        /// <param name="alignY">The vertical alignment within the rectangle</param>
        public static void AlignVisualBounds(UIElement visual, Size size, Rect rect, AlignmentX alignX, AlignmentY alignY)
        {
            Point pt = new Point(0,0);

            switch (alignX)
            {
                case AlignmentX.Left:
                    pt.X = rect.X;
                    break;
                case AlignmentX.Right:
                    pt.X = rect.Right - size.Width;
                    break;
                case AlignmentX.Center:
                    pt.X = rect.X + ((rect.Width - size.Width) / 2);
                    break;
            }

            switch (alignY)
            {
                case AlignmentY.Top:
                    pt.Y = rect.Y;
                    break;
                case AlignmentY.Bottom:
                    pt.Y = rect.Bottom - size.Height;
                    break;
                case AlignmentY.Center:
                    pt.Y = rect.Y + ((rect.Height - size.Height) / 2);
                    break;
            }

            SetVisualBounds(visual, pt.X, pt.Y, size.Width, size.Height);
        }
    }


}
